// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#pragma once

#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/okex_common/api_util/auth_key.h"
#include "coin2/exchange/okex_common/api_util/rate_tracker.h"
#include "coin2/exchange/order/okex_v5.pb.h"

namespace coin2::exchange::okex_v5::api_order {

enum OkexV5OrderSubTopicId : int {
  REST_DEPOSIT = 10000,
  REST_WITHDRAWAL = 10001,
  REST_DEPOSIT_SUBACCOUNT = 10002,
  REST_WITHDRAWAL_SUBACCOUNT = 1003
};

}  // namespace coin2::exchange::okex_v5::api_order

class OkexV5NativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::OkexV5RestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using ActionType = coin2::exchange::base::order::NativePrivateClient::ActionType;
  using QueryType = coin2::exchange::okex_common::api_util::QueryType;
  using OkexRateTracker = coin2::exchange::okex_common::api_util::OkexRateTracker;
  using OkexV5OrderSubTopicId = coin2::exchange::okex_v5::api_order::OkexV5OrderSubTopicId;
  using AsioHttpContextList = std::list<std::shared_ptr<AsioHttpContext>>;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);
  AsioHttpContextList SubmitRestQueryList(const RestQueryProto& query);

 public:
  explicit OkexV5NativePrivateClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config);

  std::shared_ptr<AsioHttpContext> QueryAccountInfo();
  std::shared_ptr<AsioHttpContext> QueryFundBalance();
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(
      const std::string& inst_type,
      std::string_view after_order_id);
  std::shared_ptr<AsioHttpContext> QueryHistoryOrders(const std::string& inst_type);
  std::shared_ptr<AsioHttpContext> QueryFills(const std::string& inst_type);
  std::shared_ptr<AsioHttpContext> PlaceSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceBatchOrders(const std::vector<RestParams>& params);
  std::shared_ptr<AsioHttpContext> CancelSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelBatchOrders(const std::vector<RestParams>& params);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;

  std::shared_ptr<AsioHttpContext> QueryDeposit(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryWithdrawal(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTransfer(const RestParams& params);

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);
  std::string GetProcOrderId(int64_t proc_order_id);

  std::unordered_map<std::string, int32_t> api_block_info_;
  std::unordered_map<std::string, int32_t> api_req_info_;
  OkexRateTracker* local_rate_tracker_;
};
